# encoding:utf-8
import base64
import hashlib
import json
import urllib
import asyncio
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

import tornado.ioloop
import tornado.web
from tornado import gen
from tornado.httpclient import AsyncHTTPClient
from tornado.log import LogFormatter
from datetime import timedelta, datetime
import logging
from util import aes
import motor.motor_tornado

def init_logger(name, filepath, screen=False, level=logging.INFO):
    logger = logging.getLogger(name)
    # fmt = '[%(asctime)s %(filename)s:%(funcName)s:%(lineno)d %(levelname)s:%(name)s]%(message)s'
    file_handler = logging.handlers.TimedRotatingFileHandler(filepath, when='midnight', encoding='utf-8')
    # log_format = logging.Formatter(fmt=fmt)
    log_format = LogFormatter()
    file_handler.setFormatter(log_format)
    logger.addHandler(file_handler)
    if screen:
        handler = logging.StreamHandler()
        handler.setFormatter(log_format)
        logger.addHandler(handler)
    logger.propagate = False
    logger.setLevel(level)
    return logger


class PayHandler(tornado.web.RequestHandler):
    def __init__(self, *args, **kwargs):
        self.merchantid = None
        self.merchant_info = None
        self.remote_ip = None
        self.aes_key = None
        self.sha_key = None
        super().__init__(*args, **kwargs)

    @gen.coroutine
    def merchant_exit(self, merchantid=None):
        """
        check if merchant exit,and  ip check
        :return:
        """
        if not merchantid:
            self.merchantid = self.get_argument('merchantid')
        else:
            self.merchantid = merchantid
        # redis = yield from self.application.connect_reids()
        # redis = self.application.redis
        merchant_info = yield self.application.db.merchant.find_one({"merchantid": self.merchantid})
        if not merchant_info:
            return False
        self.merchant_info = merchant_info
        x_real_ip = self.request.headers.get("X-Real-IP")
        self.remote_ip = x_real_ip or self.request.remote_ip
        # self.remote_ip = self.remote_ip.strip()
        self.aes_key = merchant_info['AESKEY']
        self.sha_key = merchant_info['SHAKEY']
        return True

    def check_ip(self):
        ip = json.loads(self.merchant_info['ip'])
        if not ip:
            return True
        if self.remote_ip not in ip:
            return False
        return True

    def check_sign(self):
        """
        check sign
        :return:
        """
        merchantid = self.merchantid
        data = self.get_argument('data')
        timestamp = self.get_argument('timestamp')
        # secretkey + merchantid  + data + v + timestamp  + secretkey
        sign = self.get_argument('sign')
        # 获取商户密钥
        sha_key = self.sha_key
        request_obj = {
            'merchantid': merchantid,
            'data': data,
            'sign': sign,
            'timestamp': timestamp
        }
        sign_string = sha_key + request_obj['merchantid'] + request_obj['data'] + request_obj['timestamp'] + sha_key
        sign = hashlib.sha256(sign_string.encode("utf-8")).hexdigest()
        if request_obj['sign'] == sign:
            return True
        else:
            return False

    def decrypt(self):
        """
        decrypt data
        :return:
        """
        data = self.get_argument('data')
        try:
            data += '===='[len(data) % 4:]
            data = base64.urlsafe_b64decode(data)
            crypto = aes.AesEncryption(self.aes_key)
            data = crypto.decrypt(data)
        except Exception as e:
            return None
        return data

    def encrypt(self, data):
        data = json.dumps(data)
        crypto = aes.AesEncryption(self.aes_key)
        data = crypto.encrypt(data)
        return base64.urlsafe_b64encode(data).decode("utf-8")

    def niti_data(self, notify_data, result):
        encrypt_text = self.encrypt(notify_data)
        merchantid = result["MERCHANTID"]
        timestamp = result.get("RESPTIME", datetime.now().strftime('%Y%m%d%H%M%S'))
        sign_string = self.sha_key + merchantid + encrypt_text + timestamp + self.sha_key
        sign = hashlib.sha256(sign_string.encode("utf-8")).hexdigest()
        request_obj = {
            "merchantid": merchantid,
            "data": encrypt_text,
            "sign": sign,
            "timestamp": timestamp
        }
        return request_obj

    @staticmethod
    def check_ordernumber(data):
        if "ordernumber" not in data:
            return {"message": "缺少ordernumber订单号", "ret": -1}
        if not isinstance(data['ordernumber'], str):
            return {"message": "ordernumber订单号类型必须是字符串", "ret": -1}
        if len(data['ordernumber']) > 32:
            return {"message": "ordernumber订单号长度错误", "ret": -1}
        if ',' in data['ordernumber']:
            return {"message": "ordernumber订单号非法字符", "ret": -1}
        return {}


@gen.coroutine
def http_result(url, body=None, model="json"):
    http_client = AsyncHTTPClient()
    if model == "json":
        response = yield http_client.fetch(url, raise_error=False, method="POST", body=json.dumps(body),
                                           request_timeout=60)
    else:
        response = yield http_client.fetch(url, raise_error=False, method="POST", request_timeout=120,
                                           body=urllib.parse.urlencode(body))
    return response


class Application(tornado.web.Application):
    def __init__(self, handlers, debug=False):
        # Prepare IOLoop class to run instances on asyncio
        tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOMainLoop')
        self.loop = None
        self.redis = None
        self.executor = None

        super().__init__(handlers, debug=debug)

    def init_with_loop(self, loop, address=('localhost', 12580), password='PayCore#8bill'):
        self.loop = loop
        client = motor.motor_tornado.MotorClient('mongodb://cs_user:cmcc5188@localhost:12018/cs_recharge')
        self.db = client.cs_recharge

        # self.executor = ProcessPoolExecutor(max_workers=5)
